import 'dart:async';
import 'package:flutter/material.dart';
import 'package:three_js/three_js.dart' as three;

class WebglMaterialsPhysicalTransmissionAlpha extends StatefulWidget {
  const WebglMaterialsPhysicalTransmissionAlpha({super.key});

  @override
  createState() => _State();
}

class _State extends State<WebglMaterialsPhysicalTransmissionAlpha> {
  List<int> data = List.filled(60, 0, growable: true);
  late Timer timer;
  late three.ThreeJS threeJs;

  @override
  void initState() {
    timer = Timer.periodic(const Duration(seconds: 1), (t) {
      setState(() {
        data.removeAt(0);
        data.add(threeJs.clock.fps);
      });
    });
    threeJs = three.ThreeJS(
      onSetupComplete: () {
        setState(() {});
      },
      setup: setup,
      settings: three.Settings(
        enableShadowMap: true,
        useOpenGL: true,
        toneMapping: three.ACESFilmicToneMapping,
        toneMappingExposure: params['exposure'],
      ),
    );
    super.initState();
  }

  @override
  void dispose() {
    timer.cancel();
    threeJs.dispose();
    three.loading.clear();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: Stack(children: [threeJs.build()]));
  }

  late final three.OrbitControls controls;
  late final three.Mesh mesh;
  late final three.Material material;

  final Map<String, dynamic> params = {
    'color': 0xffffff,
    'transmission': 1.0,
    'opacity': 1.0,
    'metalness': 0.0,
    'roughness': 0.0,
    'ior': 1.5,
    'thickness': 0.01,
    'attenuationColor': 0xffffff,
    'attenuationDistance': 1.0,
    'specularIntensity': 1.0,
    'specularColor': 0xffffff,
    'envMapIntensity': 1.0,
    'lightIntensity': 1.0,
    'exposure': 1.0,
  };

  Future<void> setup() async {
    threeJs.renderer?.toneMappingExposure = params['exposure'];
    threeJs.scene = three.Scene();
    threeJs.scene.add(three.AmbientLight(0xffffff));

    threeJs.camera = three.PerspectiveCamera(
      40,
      threeJs.width / threeJs.height,
      1,
      2000,
    );
    threeJs.camera.position.setValues(-5, 0.5, 0);

    controls = three.OrbitControls(threeJs.camera, threeJs.globalKey);
    controls.minDistance = 5;
    controls.maxDistance = 20;
    controls.target.y = 0.5;
    controls.update();

    final hl = three.RGBELoader().setPath('assets/hdr/');
    final hdrEquirect = await hl.fromAsset('royal_esplanade_1k.hdr');

    hdrEquirect.mapping = three.EquirectangularReflectionMapping;
    final gltf = await three.GLTFLoader()
        .setPath('assets/models/')
        .fromAsset('fox.glb');
    gltf!.scene.traverse((child) {
      if (child is three.Mesh && child.material is three.MeshPhysicalMaterial) {
        mesh = child;
        material = mesh.material!;

        final color = three.Color();

        params['color'] = (color..setFrom(mesh.material!.color)).getHex();
        params['roughness'] = mesh.material!.roughness;
        params['metalness'] = mesh.material!.metalness;

        params['ior'] = mesh.material!.ior;
        params['specularIntensity'] = mesh.material!.specularIntensity;
        //params['emissiveIntensity'] = mesh.material!.emissiveIntensity;

        params['transmission'] = mesh.material!.transmission;
        params['thickness'] = mesh.material!.thickness;
        params['attenuationColor'] =
            (color..setFrom(mesh.material!.attenuationColor!)).getHex();
        params['attenuationDistance'] = mesh.material!.attenuationDistance;
      }
    });

    threeJs.scene.add(gltf.scene);
    threeJs.scene.environment = hdrEquirect;
  }
}
